import {
  isSupportedRecord,
  getDataType,
  format
} from '../utils.js'

class Play {
  constructor(args) {
    const {
      videoId,
      timeId,
      videoConfig
    } = args
    if (!videoId || !timeId) {
      console.error('LveRecord: videoId和timeId为必传项')
      return
    }
    this.video = videoId
    this.videoConfig = videoConfig
    this.time = 0 // 当前时间
    this.timer = null // 录制时间定时器
    this.timeDom = timeId // 时间展示dom
    this.stream = null
    this.recordeBlobs = [] // 二进制视频文件
    this.mediaRecorder = null // 媒体对象
    this.inputData = [] // 输入数据
    this.g = null // 生成器
  }
  /**
   * 设置录制数据
   **/
  setData = (data) => {
    if (!data) {
      console.error('LveRecord: 无数据')
      return false
    }
    if (getDataType(data) === 'string') {
      const type = getDataType(JSON.parse(data))
      if (type === 'array') {
        this.inputData =  JSON.parse(data)
      }
    } else if (getDataType(data) === 'array') {
      this.inputData =  data
    } else {
      console.warn('LveRecord: 非法数据类型，无法识别')
      return false
    }
    return true
  }
  /**
   * 开始播放
   **/
  startPlay = () => {
    this.initTimer()
    this.timer = setInterval(() => {
      this.time += 1
      this.timeDom.textContent = format(this.time)
    }, 1000)
    this.video.width = this.videoConfig.width
    this.video.height = this.videoConfig.height
    this.video.style.display = 'block'
    const can = document.createElement('canvas')
    const ctx = can.getContext('2d')
    can.width = this.videoConfig.width
    can.height = this.videoConfig.height
    ctx.fillStyle = '#fff'
    ctx.fillRect(0, 0, can.width, can.height)
    this.stream = can.captureStream(25);
    this.video.srcObject = this.stream; // 屏幕实时回显
    const isSupported = isSupportedRecord() // 判断当前浏览器是否能进行录制
    if (isSupported) { // 能录制就进行录制，不能录制也不会影响当前播放功能
      this.recordVideo(this.stream)
    }
    this.generate(can, this.inputData)
  };
  /**
   * 结束播放
   **/
  stopPlay = () => {
    this.timer && clearInterval(this.timer)
    this.time = 0
  }
  /**
   * 视频录制中
   **/
  recordVideo = (stream) => {
    this.recordeBlobs = [];
    if (!this.mediaRecorder) {
      this.mediaRecorder = new MediaRecorder(stream, {
        mimeType: 'video/webm;codecs=vp8',
      });
      this.mediaRecorder.onstop = (e) => {
        console.log('录制完成');
      };
      this.mediaRecorder.ondataavailable = (e) => {
        if (e.data && e.data.size > 0) {
          this.recordeBlobs.push(e.data);
        }
      };
      this.mediaRecorder.start(100);
    }
  }
  /**
   * 导出视频文件
   **/
  exportVideo = () => {
    if (!this.mediaRecorder) {
      console.warn('LveRecord: 录制对象没有被初始化，请确定你的浏览器是否支持录制')
      return
    }
    this.mediaRecorder.stop();
    // stream.getTracks().forEach((track) => track.stop());
    // stream = null;
    if (this.recordeBlobs.length === 0) {
      console.warn('LveRecord: 无录制后文件')
      return
    }
    const blob = new Blob(this.recordeBlobs, { type: 'video/webm;codecs=vp8' });
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = url;
    a.download = '屏幕录制.webm';
    document.body.appendChild(a);
    a.click();
    setTimeout(() => {
      document.body.removeChild(a);
      window.URL.revokeObjectURL(url);
    }, 100);
  }
  /**
   * 异步子逻辑执行，所有单个操作都在此处
   **/
  asyncThunk = (can, item) => {
    const ctx = can.getContext('2d')
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        // 涂鸦绘制
        if (item.f === 'pen') {
          if (item.s === 'start') {
            ctx.beginPath()
            ctx.moveTo(item.x, item.y)
            ctx.stroke()
          } else if (item.s === 'ing') {
            ctx.lineTo(item.x, item.y)
            ctx.stroke()
          } else {
            ctx.closePath()
          }
        // 背景图片插入
        } else if (item.f === 'image') {
          this.drawImageToCanvas(can, item)
        // 录屏时系统操作
        } else {
          // 结束录制
          // if (item.s === 'stop') {
          //   reject('end')
          // }
        }
        resolve('ing')
      }, item.t * 1000);
    })
  }
  /**
   * 生成器初始化
   **/
  generate = (can, arr) => {
    const _this = this
    function* arrFlat(arr) { //迭代器返回一个迭代器对象
      if (Array.isArray(arr)) { // 内节点
        for(let i=0; i < arr.length; i++) {
            yield* arrFlat(arr[i]); // (*) 递归
        }
      } else {                      
        yield arr
      }
    }
    const list = [...arrFlat(arr)]
    function* gen(list) {
      for (const item of list) {
        yield _this.asyncThunk(can, item) 
      }
    }
    this.g = gen(list)
    let res = this.g.next()
    let promise = res.value
    let done = res.done
    const fn = () => {
      if (done) {
        this.stopPlay()
        return Promise.resolve(promise);
      }
      promise.then((data) => {
        // done为true，promise是 生成器函数的返回值。注意这里的next参数才是上面data2的赋值
        res = this.g.next(data);
        promise = res.value;
        done = res.done;
        // 继续往前走
        fn();
      });
    }
    fn()
  }
  /**
   * 绘制图片到canvas上(视频区)
   **/
  drawImageToCanvas = (can, item) => {
    const ctx = can.getContext('2d')
    const img = new Image;
    img.src = item.s;
    img.onload = () => {
      if (item.o.type === 'cover') {
        ctx.drawImage(img, 0, 0, can.width, can.height);
      } else {
        ctx.drawImage(img, 0, 0, can.height * item.o.width / item.o.height, can.height);
      }
    }
  }
  /**
   * 时间展示初始化
   **/
  initTimer = () => {
    this.timeDom.textContent = format(this.time)
  }
}

export default Play